package com.mobile.web.login;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mobile.service.inter.system.FunctionService;
import com.mobile.service.inter.system.UserService;
import com.mobile.web.base.BaseController;
import com.mobile.web.config.jwt.JwtRealm;
import com.mobile.util.JwtUtil;
import com.mobile.util.RedisUtil;
import com.mobile.util.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import redis.clients.jedis.Jedis;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.*;

/**
 * 用户登录API接口
 *
 * @author Administrator
 * @version 0.1 2021-01-15 初版
 *
 */
@RestController
@RequestMapping("/login")
public class LoginController extends BaseController{

	@Resource(name="userService")
	private UserService userService;
	@Value("${static.file.path}")
	String path;
	@Autowired
	FunctionService functionService;
	@Autowired
	private JwtRealm realm;
	@Autowired
	private CacheManager cacheManager;
	/**访问系統登录页
	 * @return
	 */
	@PostMapping(value="/login_toLogin")
	@ResponseBody
	public Object toLogin() {
		Map<String,Object> map = new HashMap<>();
		PageData pd = this.getPageData();

		try {
			// 系統参数设定
			this.setLoginPd(pd);
			map.put("pd",pd);
			map.put(Const.ACTION_RESULT,Const.ACTION_RESULT_TO_LOGIN);
		} catch (Exception e) {
			map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_EXCEPTION);
			map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("E0016"));
			logger.error(e.getMessage(), e);
		}

		return AppUtil.returnObject(pd, map);
	}

	/**
	 * 系统登录处理
	 *
	 */
	@PostMapping(value="/toLogin")
	public Object login() {
		Map<String,String> map = new HashMap<>();
		PageData pd = this.getPageData();
		Jedis jedis = RedisUtil.getJedis();
		try {
			// 获取登录用户数据
			String userCode = pd.getString("userCode");
			pd.put("userPassword", pd.getString("passwd"));
			PageData user = userService.getUserByCode(userCode);
			if(user != null){
				userCode = user.get("user_code").toString();
				pd.put("userCode", userCode);
				// 验证用户账号是被锁
				if(Const.IS_LOCKED_0.equals(user.getString("is_locked"))) {
					// 用户名账号已被锁定
					logBefore(logger, pd.getString("userCode") + MessageUtil.getMessage("E0051"));
					map.put(Const.ACTION_RESULT,Const.ACTION_RESULT_FAILED);
					map.put(Const.ACTION_MESSAGE,MessageUtil.getMessage("E0051"));
					// 返回结果
					return AppUtil.returnObject(new PageData(), map);
				} else if(Const.IS_LOCKED_2.equals(user.getString("is_locked"))){
					// 用户名账号已被逻辑删除
					logBefore(logger, pd.getString("userCode") + MessageUtil.getMessage("E0054"));
					map.put(Const.ACTION_RESULT,Const.ACTION_RESULT_FAILED);
					map.put(Const.ACTION_MESSAGE,MessageUtil.getMessage("E0054"));
					// 返回结果
					return AppUtil.returnObject(new PageData(), map);
				}//用户名或密码错误
				else if (!user.get("user_password").equals(EncryptUtil.encrypt(pd.getString("userPassword").trim() + user.getString("secret_key")))) {
					map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_FAILED);
					map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("E0023"));
					return AppUtil.returnObject(pd, map);
				}
//				jwt校验
				String token = JwtUtil.sign(pd.getString("userCode"), String.valueOf(System.currentTimeMillis()));
				map.put("token", token);
				String tokenKey = userCode + "-" + Const.USER_TOKEN+"-"+token;
				jedis.set(tokenKey, "");
				//设置redis token超时时间-Web端:8h(与jwt配置同步) App端无限制(用于免登录)
				if (StringUtil.isEmpty(pd.get("isApp"))) {
					jedis.expireAt(tokenKey,(System.currentTimeMillis()+JwtUtil.EXPIRE_TIME)/1000);
				}
				user.put("lastLogin", DateUtil.getTime());
				user.put("userCode",pd.getString("userCode"));
				user.put("updateUser",pd.getString("userCode"));
				user.put("updateTime", DateUtil.getTime());
				//更新登录时间
				userService.updateUser(user);

				// 保存用户按钮权限信息到redis
				PageData rfaPd = new PageData();
				rfaPd.put("userCode", pd.getString("userCode"));
				List<PageData> rfaButtonFunctionList = functionService.getFunctionAuthData(rfaPd);
				BigInteger menuAuth = RightsHelper.sumRights(rfaButtonFunctionList);
				jedis.hset(Const.SESSION_QX_MENU, userCode, JSON.toJSONString(menuAuth));
				// 验证成功场合
				map.put(Const.ACTION_RESULT,Const.ACTION_RESULT_SUCCESS);
				logBefore(logger, pd.getString("userCode") + MessageUtil.getMessage("I0002"));

			}else{
				// 用户名或密码输入错误。
				logBefore(logger, pd.getString("userCode") + MessageUtil.getMessage("E0054"));
				map.put(Const.ACTION_RESULT,Const.ACTION_RESULT_FAILED);
				map.put(Const.ACTION_MESSAGE,MessageUtil.getMessage("E0054"));
			}
		}  catch (AuthenticationException e) {
			// SHIRO身份验证失败。
			logBefore(logger, pd.getString("userCode") + MessageUtil.getMessage("E0023"));
			map.put(Const.ACTION_RESULT,Const.ACTION_RESULT_FAILED);
			map.put(Const.ACTION_MESSAGE,MessageUtil.getMessage("E0023"));
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
			map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_EXCEPTION);
			map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("E0016"));

		} finally {
			jedis.close();
		}

		// 返回结果
		return AppUtil.returnObject(new PageData(), map);
	}

	/**
	 * 获取当前登录用户系统菜单数据
	 *
	 */
	@GetMapping(value="/getMenu")
	@ResponseBody
	public Object getMenu(){
		Map<String,Object> map = new HashMap<>();
		PageData pd = this.getPageData();
		Jedis jedis = RedisUtil.getJedis();
		try{
			List<PageData> allmenuList;

			//读取redis中的用户信息(单独用户信息)
			PageData user = JSONObject.parseObject(jedis.hget(Const.SESSION_USER, this.getUserCode()),PageData.class);
			if (user != null) {
				//当前登录账号对应的菜单权限放入session中
				allmenuList = this.getAttributeMenu(this.getUserCode());
				user.remove("user_password");
				user.remove("secret_key");
				map.put("user", user);
				map.put("menuList", allmenuList);
				map.put(Const.ACTION_RESULT,Const.ACTION_RESULT_SUCCESS);
			}else {
				map.put(Const.ACTION_RESULT,Const.ACTION_RESULT_TO_LOGIN);
			}
		} catch(Exception e){
			map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_EXCEPTION);
			map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("E0016"));
			logger.error(e.getMessage(), e);
		} finally {
			jedis.close();
		}

		pd.put("SYSNAME", Tools.readTxtFile(Const.SYSNAME)); //读取系统名称
		map.put("pd",pd);
		return AppUtil.returnObject(pd, map);
	}

	/**
	 * 退出登录
	 * @return
	 */
	@PostMapping(value="/signOut" )
	@ResponseBody
	public Object signOut(){
		Map<String,Object> map = new HashMap<>();
		PageData pd = this.getPageData();
		Jedis jedis = RedisUtil.getJedis();
		try{
			String userCode = this.getUserCode();

			jedis.hdel(Const.SESSION_USER,userCode);
			jedis.hdel(Const.SESSION_allmenuList,userCode);
			jedis.hdel(Const.SESSION_QX_MENU,userCode);
			jedis.hdel(Const.SESSION_USERNAME,userCode);
			jedis.hdel(Const.SESSION_USERCODE,userCode);
			jedis.hdel(Const.SESSION_USERROLE,userCode);
			//销毁token
			jedis.del(userCode +"-"+ Const.USER_TOKEN+"-"+this.getToken());
			Subject subject = SecurityUtils.getSubject();
			//清除缓存
			cacheManager.getCache(Const.USER_AUTHOR_CACHE).remove(subject.getPrincipals());
			subject.logout();
			pd.put("msg", pd.getString("msg"));
			pd = this.setLoginPd(pd);	//设置登录页面的配置参数

			map.put(Const.ACTION_RESULT,Const.ACTION_RESULT_SUCCESS);
			return AppUtil.returnObject(pd, map);
		} catch(Exception e){
			map.put(Const.ACTION_RESULT,Const.ACTION_RESULT_EXCEPTION);
			map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("E0016"));
			logger.error(e.getMessage(), e);
		}finally {
			jedis.close();
		}
		return AppUtil.returnObject(pd, map);
	}

	/**菜单缓存
	 * @param userCode
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public List<PageData> getAttributeMenu( String userCode) throws Exception{
		List<PageData> allmenuList;
		Jedis jedis = RedisUtil.getJedis();
		if(null == jedis.hget( Const.SESSION_allmenuList,userCode)){
			//重新获取权限值
			PageData rfaPd = new PageData();
			rfaPd.put("userCode", userCode);
			List<PageData> rfaButtonFunctionList = functionService.getFunctionAuthData(rfaPd);
			BigInteger menuAuth = RightsHelper.sumRights(rfaButtonFunctionList);
			jedis.hset(Const.SESSION_QX_MENU, userCode, JSON.toJSONString(menuAuth));
			//获取所有菜单
			allmenuList = functionService.listAllMenuQx("0");
			//根据角色权限获取本权限的菜单列表
			allmenuList = this.readMenu(allmenuList);
			//菜单权限放入session中
			jedis.hset(Const.SESSION_allmenuList, userCode, JSON.toJSONString(allmenuList));
		}else{
			allmenuList = JSONArray.parseArray(jedis.hget(Const.SESSION_allmenuList, userCode), PageData.class);
		}
		jedis.close();
		return allmenuList;
	}

	/**根据角色权限获取本权限的菜单列表(递归处理)
	 * @param menuList：传入的总菜单
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<PageData> readMenu(List<PageData> menuList){
		Jedis jedis = RedisUtil.getJedis();
		for(int i=0;i<menuList.size();i++){
			menuList.get(i).put("hasMenu",
					RightsHelper.testRights(
							jedis.hget(Const.SESSION_QX_MENU, this.getUserCode()),
							menuList.get(i).get("function_id").toString()));
			if((boolean) menuList.get(i).get("hasMenu")){
				//是：继续排查其子菜单
				this.readMenu((List<PageData>)menuList.get(i).get("subMenu"));
			}
		}
		jedis.close();
		return menuList;
	}

	/**设置登录页面的配置参数
	 * @param pd
	 * @return
	 */
	public PageData setLoginPd(PageData pd){
		pd.put("SYSNAME", Tools.readTxtFile(Const.SYSNAME)); 		//读取系统名称

		String strLOGINEDIT = Tools.readTxtFile(Const.LOGINEDIT);	//读取登录页面配置

		if(!StringUtil.isEmpty(strLOGINEDIT)){
			String[] strLo = strLOGINEDIT.split(",fh,");
			if(strLo.length == 2){
				pd.put("isZhuce", strLo[0]);
				pd.put("isMusic", strLo[1]);
			}
		}
		return pd;
	}

}
